﻿using AutoMapper;
using SqlSugar;
using SqlSugar.Extensions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Zhao.Common.EnumEntity;
using Zhao.Common.Helper;
using Zhao.IServer.Log;
using Zhao.IServer.menu;
using Zhao.Models.DTO;
using Zhao.Models.Entity;
using Zhao.Repository.Base;
using Zhao.Repository.UnitOfWork;
using Zhao.Service;

namespace Zhao.Service.menu
{
    public class MenusServer : BaseService<Menus>, IMenusServer
    {
        private readonly IMapper _mapper;
        private readonly IUnitOfWork _unitOfWork;
        private readonly ILogsServer _logs;
        public MenusServer(IBaseRepository<Menus> baseDal, IUnitOfWork unitOfWork, IMapper mapper, ILogsServer logs) : base(baseDal, unitOfWork)
        {
            _mapper = mapper;
            _unitOfWork = unitOfWork;
            _logs = logs;
        }

        public async Task<PageModel<Menus>> GetMenuTreePageAsync(int pageIndex, int pageSize, string? keywords)
        {

            var treeMeueList = _Client
                  .Queryable<Menus>()
                  .Select(m1 => new Menus
                  {
                      Id = m1.Id,
                      ParentId = m1.ParentId,
                      MenuText = m1.MenuText,
                      WebUrlName = m1.WebUrlName,
                      VueFilePath = m1.VueFilePath,
                      Icon = m1.Icon,
                      WebUrl = m1.WebUrl,
                      IsLeafNode = m1.IsLeafNode,
                      OrderBy = m1.OrderBy,
                      CreateTime = m1.CreateTime,
                  });

            var treeDataList = await treeMeueList.ToTreeAsync(it => it.Children, it => it.ParentId, default(Guid));

            //对顶层菜单做查询
            treeDataList = treeDataList
                  .WhereIF(!keywords.IsNullOrEmpty(), t => t.MenuText.Contains(keywords))
                  .ToList();

            treeDataList = OrderByData(treeDataList);

            PageModel<Menus> pageModel = new PageModel<Menus>()
            {
                data = treeDataList.Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList(),
                PageIndex = pageIndex,
                PageSize = pageSize,
                count = treeDataList.Count(),
                msg = treeDataList.Count() == 0 ? "未查询到任何数据" : ""
            };

            return pageModel;
        }


        /// <summary>
        /// 递归支持查询---全部都是内存操作
        /// </summary>
        /// <param name="treeDataList"></param>
        /// <returns></returns>
        private List<Menus> OrderByData(List<Menus> treeDataList)
        {
            List<Menus> datalist = treeDataList.OrderBy(m => m.OrderBy).ToList();
            foreach (var item in datalist)
            {
                if (item.Children != null && item.Children.Count > 0)
                {
                    item.Children = OrderByData(item.Children);
                }
            }
            return datalist;
        }


        /// <summary>
        /// 多处使用
        /// 1、作为菜单修改项目----需要传递Id 来过滤掉当前菜单的选项和子选项
        /// 2、查询路由数据---不用传值；就查询所有的数据
        /// <param name="Id"></param>
        /// <returns></returns>
        public async Task<List<Menus>> GetMenuTreeAsync(Guid Id = default)
        {
            Expressionable<Menus> expressionable = new Expressionable<Menus>();
            expressionable.AndIF(Id != default, c => c.Id != Id);

            return await _Client.Queryable<Menus>()
                 .Where(expressionable.ToExpression())
                 .ToTreeAsync(it => it.Children, it => it.ParentId, default(Guid));
        }


        /// <summary>
        /// 修改或者新增菜单
        /// </summary>
        /// <param name="menudto"></param>
        /// <returns></returns>
        public async Task<ApiResult> AddOrUpdateMenuAsync(MenuDTO menudto)
        {
            // 如果是修改菜单，则先查询原菜单数据
            Menus originalMenu = null;
            if (menudto.Id != default)
            {
                originalMenu = await _Client.Queryable<Menus>().Where(c => c.Id == menudto.Id).FirstAsync();
            }

            // 如果设置了归属菜单，需要检查是否归属到了其子菜单下
            if (menudto.Id != default) // 修改操作
            {
                string sql = @"
            WITH temp AS (
                SELECT [Id] FROM [dbo].[Menus] WHERE Id = @Id
                UNION ALL
                SELECT a.[Id] FROM [dbo].[Menus] a
                INNER JOIN temp ON a.[ParentId] = temp.[Id]
            )
            SELECT * FROM temp;";
                List<Guid> childGuidList = _Client.Ado.SqlQuery<Guid>(sql, new { menudto.Id });
                if (menudto.ParentId != null && childGuidList.Contains(menudto.ParentId.Value))
                {
                    return await Task.FromResult(new ApiResult()
                    {
                        Success = false,
                        Message = "菜单不能归属于当前菜单的子菜单"
                    });
                }
            }

            // 映射DTO到实体
            Menus menu = _mapper.Map<MenuDTO, Menus>(menudto);
            
            // 去除WebUrlName和VueFilePath中的多余空格
            if (!string.IsNullOrEmpty(menu.WebUrlName))
            {
                menu.WebUrlName = menu.WebUrlName.Trim();
            }
            
            if (!string.IsNullOrEmpty(menu.VueFilePath))
            {
                menu.VueFilePath = menu.VueFilePath.Trim();
            }
            
            menu.WebUrl = $"/{menu.WebUrlName}";
            menu.Status = menudto.statu ? (int)StatusEnum.Normal : (int)StatusEnum.Frozen;

            // 仅在以下情况调整排序：新增菜单 或者 是修改操作且排序值改变了
            bool needReorder = menu.Id.Equals(default) || originalMenu != null && originalMenu.OrderBy != menudto.OrderBy;
            List<Menus> upOrderList = null;
            if (needReorder)
            {
                // 找出需要调整排序的同级菜单（排除当前的菜单）
                upOrderList = _Client.Queryable<Menus>()
                    .OrderBy(c => c.OrderBy)
                    .Where(c => c.OrderBy >= menudto.OrderBy && c.ParentId == menudto.ParentId && c.Id != menudto.Id)
                    .ToList();

                // 调整排序，从当前order开始依次递增
                if (upOrderList != null && upOrderList.Count > 0)
                {
                    int order = menu.OrderBy;
                    foreach (var men in upOrderList)
                    {
                        order++;
                        men.OrderBy = order;
                    }
                }
            }

            try
            {
                // 开启事务，确保数据一致性
                _unitOfWork.BeginTran();
                // 如果设置了父级，且父级数据存在，则更新父级为非叶节点
                if (menu.ParentId != default)
                {
                    Menus uMenu = await _Client.Queryable<Menus>().Where(c => c.Id == menu.ParentId).FirstAsync();
                    uMenu.IsLeafNode = false;
                    await _Client.Updateable(uMenu)
                        .UpdateColumns(c => new { c.IsLeafNode })
                        .ExecuteCommandAsync();
                }

                // 插入或更新菜单数据
                if (menu.Id.Equals(default))
                {
                    await _Client.Insertable(menu).ExecuteCommandAsync();
                }
                else
                {
                    await _Client.Updateable(menu).ExecuteCommandAsync();
                }

                // 如果需要排序调整，则更新对应的同级菜单记录
                if (needReorder && upOrderList != null && upOrderList.Count > 0)
                {
                    await _Client.Updateable(upOrderList)
                        .UpdateColumns(c => new { c.OrderBy })
                        .ExecuteCommandAsync();
                }
                await _logs.Info($"菜单修改或插入,{menu.ToJson()}");
                _unitOfWork.CommitTran();
            }
            catch (Exception ex )
            {
                await _logs.Error($"菜单修改或插入,{menu.ToJson()},原因:{ex.Message}");
                // 遇到异常时回滚事务，确保数据一致性
                _unitOfWork.RollbackTran();
                return await Task.FromResult(new ApiResult()
                {
                    Success = false,
                    Message = "操作失败"
                });
            }

            return await Task.FromResult(new ApiResult()
            {
                Success = true,
                Message = "操作成功"
            });
        }


        /// <summary>
        /// 逻辑删除菜单
        /// </summary>
        /// <param name="menuId"></param>
        /// <returns></returns>
        public async Task<bool> DelMenuAsync(Guid menuId)
        {
            //--需要解决的问题 如果当前菜单以及分配给对应的角色 考虑是否给删除 如果给删除 已经分配的角色该如何解决--

            //把当前删除的菜单状态改为已删除
            Expressionable<Menus> expressionable = new Expressionable<Menus>();
            expressionable.And(c => c.Id == menuId);
            Menus upMenu = _Client.Queryable<Menus>().First(expressionable.ToExpression());
            upMenu.IsDeleted = true;

            //判断上级菜单是否是叶节点，如果是叶节点，需要维护上级菜单的叶节点的字段
            //查询当前要删除的菜单的父级菜单是否还有其他的子节点 如果没有就将当前的父级菜单改为叶节点
            bool isContains = await _Client.Queryable<Menus>().AnyAsync(m => m.ParentId == upMenu.ParentId && m.Id != upMenu.Id);
            try
            {
                //启动事务
                await _Client.Ado.BeginTranAsync();
                //如果没有子节点了就是false  有子节点就是true
                if (!isContains)
                {
                    //修改当前的父节点为叶节点 允许删除
                    Menus parentMen = _Client.Queryable<Menus>().First(c => c.Id == upMenu.ParentId);
                    parentMen.IsLeafNode = true;
                    await _Client.Updateable(parentMen)
                        .UpdateColumns(c => new { c.IsLeafNode })  //按需更新
                        .ExecuteCommandAsync();
                }
                await _Client.Updateable(upMenu)
                     .UpdateColumns(c => new { c.IsDeleted })  //按需更新
                    .ExecuteCommandAsync();
                await _Client.Ado.CommitTranAsync();

                await _logs.Info($"菜单逻辑删除,{upMenu.ToJson()}");
                return await Task.FromResult(true);

            }
            catch (Exception ex)
            {
                await _logs.Error($"菜单逻辑删除,{upMenu.ToJson()},原因:{ex.Message}");
                //如失败回滚事务
                await _Client.Ado.RollbackTranAsync();
                return await Task.FromResult(false);
            }

        }



        /// <summary>
        /// 获取菜单树列表,根据用户归属来获取
        /// </summary>
        /// <param name="userId"></param>
        /// <returns></returns>
        public async Task<List<Menus>> GetMenusTreeList(int userId)
        {
            //根据用户Map的菜单---到用户菜单关联中去计算属于用户的菜单属于
            //【用户设置菜单的数据】
            var userMenuMapList = _Client.Queryable<RoleMenuMap, Menus>
               ((um, m) => um.MenuId == m.Id)
               .Where((um, m) =>um.RoleId==userId)
               .Select((um, m) => m)//只返回Menus表的数据
               .Distinct();//去重

            var list1 = await userMenuMapList.ToListAsync();

            //根据用户Id关联角色Map表，根据用户的角色计算出的菜单
            var roleMenuMapList = _Client.Queryable<Roles, RoleMenuMap, Menus>
                ((ur, rm, m) => ur.RoleID == rm.RoleId && rm.MenuId == m.Id)
                .Where((ur, rm, m) => rm.RoleId==userId)
                .Select((ur, rm, m) => m)//只返回Menus表的数据
                .Distinct();

            var list2 = await roleMenuMapList.ToListAsync();

            //以上两个求并集--取树形结构
            var alltreeList = await _Client.Union(userMenuMapList, roleMenuMapList)
                .OrderBy(m => m.OrderBy)
                .ToTreeAsync(it => it.Children, it => it.ParentId, default(Guid));


            return alltreeList;
        }

    }
}
